//Gary McGuire's method of fast finding of all UA of size up to 12 in a fixed grid
#define _CRT_SECURE_NO_WARNINGS

#include <fstream>
#include <iostream>
//
//using std::vector;
//using std::cout;
//using std::endl;
//#include "uset.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sk_typ0.h"
#include "sk_tables0.h"

#include "unav12_27.h"
#include "Zhousrcd.h"
using namespace std;
#include "unav12tables.cpp"
//#define arraysize(a) static_cast< int >( sizeof(a) / sizeof((a)[0]) )

extern GAME  game[50],Tblgame;
extern long long cptg[30];
UA_XY27 ua_xy27;

int UA::Compare(UA & x){
	if(n<x.n) return -1;
	if(n>x.n) return 1;
	for(int i=0;i<3;i++){
		if(bf[i]<x.bf[i]) return -1;
		if(bf[i]>x.bf[i]) return 1;
	}
	return 0; // this is equal as usual
}


int UA::SupersetOf(UA & x){// assumed *this > x
	if(n==x.n) return 0; // no super set if equal and a!=b
	for(int i=0;i<3;i++)	if(bf[i] ^ (bf[i] & x.bf[i])) return 0;
	return 1; // no extra bit in x 
}

void UA::Print(){
	char ws[82];
	cout <<String(ws)<< " count=" << n;
}

void UA_XY27::UAG::BuildTbox(){
	nbox=0;
	if(bf[0] & 07007007) tbox[nbox++]=0;
	if(bf[0] & 070070070) tbox[nbox++]=1;
	if(bf[0] & 0700700700) tbox[nbox++]=2;
	if(bf[1] & 07007007) tbox[nbox++]=3;
	if(bf[1] & 070070070) tbox[nbox++]=4;
	if(bf[1] & 0700700700) tbox[nbox++]=5;
	if(bf[2] & 07007007) tbox[nbox++]=6;
	if(bf[2] & 070070070) tbox[nbox++]=7;
	if(bf[2] & 0700700700) tbox[nbox++]=8;
	for(int i=0;i<nbox; i++){
		int box=tbox[i],relbox=box%3,band=box/3,dj=27*band;
		unsigned int & bfx=bf[band];
		byte * tt=cellsInGroup[relbox+18];
		nboxclues[i]=0;
		for(int ib=0;ib<9;ib++){
			int rcell=tt[ib];
			if(bfx & (1<<rcell)) boxclues[i][nboxclues[i]++]=rcell+dj;
		}

	}
	
}


void UA_XY27::UAG::Print(int index,int ii){
	char ws[82];
	cout <<String(ws)<<"UAG size " << n << " boxes(0-8) ";
	for(int i=0;i<nbox;i++) cout << " " <<  tbox[i];
	if(index) cout << " i=" <<ii;
	cout <<endl;
}

void UA_XY27::UAG::PrintDet(){
	for(int i=0;i<nbox;i++){
		cout << "box "<<tbox[i]<<" ";
		int nb=nboxclues[i],*tc=boxclues[i];
		for(int j=0;j<nb;j++){
			cout << tc[j]<<" ";
		}
		cout << endl;
	}

}

void  UA_XY27::TUAG::PrintAllFull(){	
	for(int i=0;i<nua;i++){
		t[i].Print(1,i);
		t[i].PrintDet();

	}
}

int UA_XY27::TUAG::AddUA(){
	// try to add a pattern in the TUA table  sorted
	// no redundancy  no existing subset/superset of that pattern
	for(int iua=0;iua<nua;iua++){
		int ir=wt.Compare(t[iua]);
		if(!ir) return 0; //redundant
		if(ir>0){// check for a subset
			if (wt.SupersetOf(t[iua])) return 0;
			continue; 
		}
		// insert the new here
		UAG temp[5000]; // temporary for memcpy
		memcpy (temp,&t[iua],sizeof UAG*(nua-iua+1)); // why +1 ??
		memcpy (&t[iua+1],temp,sizeof UAG*(nua-iua+1)); 
		t[iua]=wt;	
		nua++;
		// and check if new subsets to discard??
		for(int i=iua+1;i<nua;i++){ 
			if(t[iua].SupersetOf(wt)){ // kill superset of last entry
				if(nua-(i+1)){// shift if  the last
					memcpy (temp,  &t[i+1],sizeof UAG*(nua-i));// should be nua-i-1
					memcpy (&t[i],  temp, sizeof UAG*(nua-i));
				}
				nua--;
				i--; //restart the loop at the same place
			}
		}
		return 1;		
	}
	// add the new to the end
	t[nua++]=wt;
	return 1;		
}
void  UA_XY27::TUAG::PrintPerm(){
	char ws[82];
	for(int i=0;i<=ispot;i++){
		UAG & x=t[spt[i].ua];
		int box=x.tbox[spt[i].ind];
		BF3 wb=x;
		wb&=bf3boxes[box];
		cout << wb.String(ws) << " perm " << i<< 
			" UA=" <<spt[i].ua<< " n=" << x.n <<endl;
	}
}

void UA_XY27::TUAG::Loadgamex(BF3 & x,int igame){
	GAME & g=game[igame];
	memcpy(g.F,Tblgame.F,4*54);
	for(int i=0;i<27;i++){
		if(x.bf[0] & (1<<i)) g.Seta(puz0[i],i);
		int j=i+27;		if(x.bf[1] & (1<<i)) g.Seta(puz0[j],j);
		j=i+54;			if(x.bf[2] & (1<<i)) g.Seta(puz0[j],j);
	}
}

void UA_XY27::TUAG::Loadgame0(BF3 & x){
	GAME & g=game[0];
	game[0]=Tblgame;
//	memcpy(g.F,Tblgame.F,4*54);
	for(int i=0;i<27;i++){
		if(x.bf[0] & (1<<i)) g.Seta(puz0[i],i);
		int j=i+27;		if(x.bf[1] & (1<<i)) g.Seta(puz0[j],j);
		j=i+54;			if(x.bf[2] & (1<<i)) g.Seta(puz0[j],j);
	}
}

void UA_XY27::CheckPattern( UnavPat & up){
	// see if, for each group, all cells in the group contain the same digit
	for ( int k = 0 ;  k<up.digits;  k++ ){
		byte *  myd=up.groups[ k ].data;
		int dig=grid[myd[0 ]];// digit in the first location
		for ( int d =1; d< up.groups[ k ].size ;  d ++ )
			if ( grid[ myd[ d ] ]-dig )		return;
	}
	// check if it is necessary to check for different digits ??
	// found an instance of this particular pattern
	UAG & wt=tuag.wt;
	wt.Initbf();
	for ( int k = 0;  k < up.digits;  k++ )
		for ( int l = 0;  l < up.groups[ k ].size;  l++ ){
			int w=up.groups[ k ].data[ l ],cell=backgrid[w]; 
			if(transpose) cell=Tbltranspose_d[cell];
			wt.cells[wt.n++]=cell;
			wt.Set(cell);
		}// end for for
	tuag.AddUA(); 

}  

void UA_XY27::CollectMoreGo(char * p, int ir,int ic,int transp){
	transpose=transp;
	// build the grid 2x2
	for ( int y = 0;  y < 6;  y++ ) for ( int x = 0;  x < 6;  x++ ){
		int a=9 * y + x,b= 9*rows[y] + cols[x];
        grid[ a] = p[ b ];  
		backgrid[a]=b;
	}
    // we also need that a_23 == a_41 or a_23 == a_42 or a_21 == a_42
    // we also need that 11 =27 or 11 =28 or 9 =28
    if (grid[11] != grid[27]  &&   grid[11] != grid[28]  
		    &&  grid[9] != grid[28] )  return;
    int type = 0;					// type I
    if(grid[11]==grid[28]) type = 3;// type II (grid[23]==grid[42])
    else if (grid[9]==grid[28]){//  ( grid[ 21 ] == grid[ 42 ] )
         type = 1;            // type III
         if (grid[11]==grid[27]) //( grid[ 23 ] == grid[ 41 ] )
               type = 2;         // type I + type III
    } 
	UnavPat *tt[4]={unavpat2x2_0,unavpat2x2_1,unavpat2x2_2,unavpat2x2_3},
		    * mytt=tt[type];
    // then search for all 2x2 patterns
    for ( int t = 0;  t < cntpat2x2[ type ];  t++ )
        CheckPattern( mytt[ t ]  );
	// for each 2x3 
    for ( int k = 0;  k < 3;  k++ )        {
		cols= tpermorder[ (ic / 3) * 36 + (ic % 3) * 12 + k * 2 ];
        // set up permuted grid -- top three rows of the right-most stack
        for ( int y = 0;  y < 6;  y++ ) for ( int x = 6;  x < 9;  x++ ){
			int a=9 * y + x,b= 9*rows[y] + cols[x];
			grid[ a] = p[ b ];  
			backgrid[a]=b;
		}
        // search for 2x3 patterns
		UnavPat *tt3[4]={unavpat2x3_0,unavpat2x3_1,unavpat2x3_2,unavpat2x3_3},
		    * mytt3=tt3[type];
		for ( int t = 0;  t < cntpat2x3[ type ];  t++ )
			CheckPattern(  mytt3[ t ]);

		for ( int l = 0;  l < 3;  l++ ){
			rows= tpermorder[(ir / 3) * 36 + (ir % 3) * 12 + l*2];
            // set up permuted grid -- bottom band
            for ( int y=6;  y< 9;  y++ )   for ( int x=0;  x<9;  x++ ){
				int a=9 * y + x,b= 9*rows[y] + cols[x];
				grid[ a] = p[ b ];  
				backgrid[a]=b;
			}

			UnavPat *tt33[4]={unavpat3x3_0,unavpat3x3_1,unavpat3x3_2,unavpat3x3_3},
				 * mytt33=tt33[type];
			// finally search for 3x3 patterns
			for ( int t = 0;  t < cntpat3x3[ type ];  t++ )
				CheckPattern(  mytt33[ t ]);

		}
	}

}

void UA_XY27::CollectMoreGo1(char * p,  int ir,int ic,int transp){
	transpose=transp;
	// build the grid 1x2
//	strcpy(grid,empty_puzzle);// provisoire pour test
//	grid[54]=0;
	for ( int y = 0;  y < 6;  y++ ) for ( int x = 0;  x < 6;  x++ ){
		int a=9 * y + x,b= 9*rows[y] + cols[x];
        grid[ a] = p[ b ];  
		backgrid[a]=b;
	}
//	cout <<grid<< "morego1 transpose="<< transpose<<endl;
	// first search for all 1x2 patterns
	for(int i=0;i<8;i++)  
			CheckPattern (unavpat1x2[i]);
    for ( int k = 0;  k < 3;  k++ )        {
		cols= tpermorder[ (ic / 3) * 36 + (ic % 3) * 12 + k * 2 ];
        // set up permuted grid -- top three rows of the right-most stack
        for ( int y = 0;  y < 3;  y++ ) for ( int x = 6;  x < 9;  x++ ){
			int a=9 * y + x,b= 9*rows[y] + cols[x];
			grid[ a] = p[ b ];  
			backgrid[a]=b;
		}
        // search for 1x3 patterns
        for ( int t = 0;  t < 74;  t++ )
			CheckPattern(  unavpat1x3[ t ]);
    }
 
}

void UA_XY27::CollectMoreUas(){
	// be sure to have a transposed grid
	char gT[82];
	for(int i=0;i<81;i++) gT[i]=entry[Tbltranspose_d[i]];
	gT[81]=0;
	// first do it for one band
	for ( int i = 0;  i < 18;  i++ )      {
		rows= tpermorder[(i / 6) * 2 * 216 + (i % 6) * 36 ];
		for ( int j = 0;  j < 108;  j++ ){
			cols= tpermorder[(j / 3) * 36 + (j % 3) * 12 ];
			int a=  9*rows[0] + cols[0] ,  d=  9*rows[1] + cols[3] ;
			// check if a_11 == a_24 in the perm 
			if(entry[a]==entry[d]) CollectMoreGo1(entry,i,j);
			if(gT[a]==gT[d]) CollectMoreGo1(gT,i,j,1);
		}// end cols
	}// end rows

	// 108 is 6 perms bands / stack + 6 perms box 1 +3 perms band/stack 2
	for ( int i = 0;  i < 108;  i++ )      {
		rows= tpermorder[(i / 3) * 36 + (i % 3) * 12 ];
		for ( int j = 0;  j < 108;  j++ ){
			cols= tpermorder[(j / 3) * 36 + (j % 3) * 12 ];
			int a=  9*rows[0] + cols[0] ,  d=  9*rows[1] + cols[3] , d1= 9*rows[3] + cols[1];
			// check if a_11 == a_24 in the perm 
			if(entry[a]==entry[d]) CollectMoreGo(entry,i,j);
			if(gT[a]==gT[d]) CollectMoreGo(gT,i,j,1);
		}// end cols
	}// end rows
}


int UA_XY27::Filter17(char * puz)   {
    strcpy(entry,puz);
	for(int i=0;i<81;i++) entry0[i]=entry[i]-'1'; // zerobased entry
	tuag.puz0=entry0;
	opg=1;
	tuag.nua=0;
	CollectMoreUas();
	int na=(tuag.nua-100)/10;
	if(0){
		if(na<0) na=0;
		if(na>29) na=29;
		cptg[na]++;
	}
	tuag.BuildTbox();
	cout << "total UAs " << tuag.nua<<endl;
//	tuag.PrintAllFull();
//	if(1) return tuag.nua;
	if(0){
		tuag.CoverSourceAndAll(ptest);
		char ws[82];
		for(int i=0;i<tuag.nuafull;i++) {
			UAG & x=tuag.t[i];
			if(x.omit) continue;
			cout<<x.String(ws)<< " " << i << endl; 
		}
	}

	cpt[0]=cpt[1]=cpt[2]=cpt[3]=cpt[4]=0;

	if(tuag.Search10()<0)		cout << "abandon" << endl;

	cout << "cpt0 " << cpt[0] << " cpt1 " << cpt[1] 
	     << " cpt2 " << cpt[2]  << " cpt3 " << cpt[3] 
		 << " cpt4 " << cpt[4] << endl;

//	cout << "expected still to work "<< cpt[0] - cpt[1] + cpt[4]<<endl;;
	return tuag.nua;
}


int UA_XY27::TUAG::Search10(){// try 10 UAs using box groups then per clue
	char ws[82];
	ispot=0;
	s=spt;
	s->ua=0;
	s->bf.Init();
next_spot:
	s->ind=-1;
	s->lim=t[s->ua].nbox;
next_value:
	if(++(s->ind) >=s->lim) goto back_track;
	// build the filter for the next spot
	BF3 & wbf=spt[ispot+1].bf;
	wbf=s->bf;
	UAG & myua=t[s->ua];
	wbf|=((BF3)myua & bf3boxes[myua.tbox[s->ind]] );
	if(ispot==10){// 10 UAs
		ua_xy27.cpt[0]++;
//		if(ua_xy27.cpt[0]<3)	SearchMoreAfter10();
		goto next_value;
	}
	// find next free UA46
	int iua=s->ua;
	while(++iua<nua)	if(!t[iua].Overlay(wbf))	break;
	//=============================== 
	if(iua<nua ){// one more UA to hint
		s++; ispot++;
		s->ua=iua;
		goto next_spot;
	}
	else {
		cout <<" stop due to no more UA available" << endl;
		DumpPath();
		Loadgame0(wbf);
		if(game[0].IsPatFinalOk()){
			cout << "the game is solved"<< endl;
			goto next_value;
		}
		else {
			Loadgame0(wbf);
			BF3 solved;
			game[0].FullUpdate(solved);
			cout <<solved.String(ws)<< "  full update the game is not solved"<< endl;
			for(int i=0;i<81;i++)
				if(ws[i]=='1') ws[i]=ua_xy27.entry[i];
			cout << ws << endl;
			goto next_value;
//		return -1; // give up if not more than 10 UAs
		}
	}
back_track:
	if(--s>=spt){ispot--; goto next_value;}
	return 0;
}

int UA_XY27::TUAG::SearchMoreAfter10(){// After 10 UA's go clue per clue
	int diag=0;
	if(ua_xy27.cpt[0]<2) diag=1;
	else return 0;
struct SPOT{
	int ind,ua,lim,*tt;
	BF3 bf;
}spots[18],*s;			
	// go back 2 steps and try one by one 
	SPT &s1=spt[ispot];
	UAG & x1 =t[s1.ua];
	int ispot2=0,lim2=17-ispot-2; // max to find here
	if(diag){
		cout << "more1 ispot="<<ispot<< " lim="<<lim2
			<< " ua="<<s1.ua<<endl;
		char ws[82];
		cout << s1.bf.String(ws)<<" depart"<<endl;
	}
		s=spots;// start now search in other UAs==========
		s->bf=s1.bf; //start with old bf 
		int iua=s1.ua;// previous UAs have a hint 
		while(++iua<nua)	if(!t[iua].Overlay(s->bf))	break;
		if(iua>=nua){return -1;}// should never be but !!!
		// we have the first free UA to start
		s->ua=iua;
next_spot:
		s->ind=-1;
		UAG & mua=t[s->ua];
		s->lim=mua.n;
		s->tt=mua.cells;
next_value:
		if(++s->ind >= s->lim) goto back_track;
		BF3 & wbf=spots[ispot2+1].bf;
		wbf=s->bf;
		wbf.Set(s->tt[s->ind]);
		iua=s->ua;
		while(++iua<nua)	if(!t[iua].Overlay(wbf))	break;
		if(iua<nua ){
			if(ispot2<lim2){
				s++; ispot2++;
				s->ua=iua;
				if(0 &&diag){
					char ws[82];
					cout << wbf.String(ws)<<" ispot2 "<<ispot2<<endl;
				}
				goto next_spot;
			}
			else {ua_xy27.cpt[3]++;goto next_value;}
		}
		//==================== we have one permutation to study
		if(ispot2==lim2){// here faster ? to check if not yet valid
			ua_xy27.cpt[1]++;
			goto next_value;
		}
		ua_xy27.cpt[2]++;
		goto next_value;
back_track:
		if(--ispot2>=0) {s--; goto next_value;}
	return 0;
}


int UA_XY27::TUAG::Search(){// try all UAs using box groups
	ispot=0;
	s=spt;
	s->ua=0;
	s->bf.Init();
next_spot:
	s->ind=-1;
	s->lim=t[s->ua].nbox;
next_value:
	if(++(s->ind) >=s->lim) goto back_track;
	// build the filter for the next spot
	BF3 & wbf=spt[ispot+1].bf;
	wbf=s->bf;
	UAG & myua=t[s->ua];
	wbf|=((BF3)myua & bf3boxes[myua.tbox[s->ind]] );
	if(0 && ispot==13){
		Loadgame0(wbf);
		if(game[0].IsPatFinalOk()){
			ua_xy27.cpt[3]++;
			goto next_value;
		}
		else ua_xy27.cpt[4]++;
	}
	// find next free UA46
	int iua=s->ua;
	while(++iua<nua)	if(!t[iua].Overlay(wbf))	break;
	//=============================== 
	if(iua<nua ){// one more UA to hint
		if(ispot<16){// not yet reached 17
			s++; ispot++;
			s->ua=iua;
			goto next_spot;
		}
		else {
			ua_xy27.cpt[4]++;
			goto next_value;
		}
	}
	//==================== we have one permutation to study	
	if(ispot>15) {ua_xy27.cpt[0]++;}//SearchMore1();} 
	else if(ispot>14) ua_xy27.cpt[1]++;
	else ua_xy27.cpt[2]++;
	goto next_value;
back_track:
	if(--s>=spt){ispot--; goto next_value;}
	return 0;
}

int UA_XY27::TUAG::SearchMore1(){// After first locked below 17
	int diag=0;
	if(ua_xy27.cpt[0]<5) diag=1;
	else return 0;
struct SPOT{
	int ind,ua,lim,*tt;
	BF3 bf;
}spots[18],*s;			
	// go back 2 steps and try one by one 
	SPT &s1=spt[ispot];
	UAG & x1 =t[s1.ua];
	int *t1=x1.boxclues[s1.ind],nt1=x1.nboxclues[s1.ind];
	int ispot2,lim2=17+1-ispot; // max to find here
	if(diag){
		cout << "more1 ispot="<<ispot<< " lim="<<lim2
			<< " nt1=" << nt1
			<< " ua="<<s1.ua<<endl;
		char ws[82];
		cout << s1.bf.String(ws)<<" depart"<<endl;
	}
	for(int i1=0;i1<nt1;i1++){
		ispot2=0;// start now search in other UAs==========
		s=spots;
		s->bf=s1.bf; //start with old bf plus the 2 settings
		s->bf.Set(t1[i1]);
		int iua=s1.ua;// previous UAs have a hint 
		while(++iua<nua)	if(!t[iua].Overlay(s->bf))	break;
		if(iua>=nua){return -1;}// should never be but !!!
		// we have the first free UA to start
		s->ua=iua;
		if(diag){
			char ws[82];
			cout << s->bf.String(ws)<<" 1 alloc"<<endl;
		}
next_spot:
		s->ind=-1;
		UAG & mua=t[s->ua];
		s->lim=mua.n;
		s->tt=mua.cells;
next_value:
		if(++s->ind >= s->lim) goto back_track;
		BF3 & wbf=spots[ispot2+1].bf;
		wbf=s->bf;
		wbf.Set(s->tt[s->ind]);
		iua=s->ua;
		while(++iua<nua)	if(!t[iua].Overlay(wbf))	break;
		if(iua<nua && ispot2<lim2){
			if(ispot2<lim2){
				s++; ispot2++;
				s->ua=iua;
				if(diag){
					char ws[82];
					cout << wbf.String(ws)<<" ispot2"<<ispot2<<endl;
				}
				goto next_spot;
			}
			else goto next_value;
		}
		//==================== we have one permutation to study
		if(ispot2>=lim2) goto next_value;
		if(ispot2==lim2-1){// here faster ? to check if not yet valid
			ua_xy27.cpt[3]++;
			goto next_value;
		}
		ua_xy27.cpt[1]++;
		goto next_value;
back_track:
		if(--ispot2>=0) {s--; goto next_value;}
	}// end i1
	return 0;
}


int UA_XY27::TUAG::SearchMore2(){// After first locked below 19
struct SPOT{
	int ind,ua,lim,*tt;
	BF3 bf;
}spots[18],*s;			
	// go back 2 steps and try one by one 
	SPT &s1=spt[ispot-1],&s2=spt[ispot];
	UAG & x1 =t[s1.ua],x2 =t[s2.ua];
	int *t1=x1.boxclues[s1.ind],nt1=x1.nboxclues[s1.ind],
		*t2=x1.boxclues[s2.ind],nt2=x1.nboxclues[s2.ind];
	int ispot2,lim2=17+1-ispot; // max to find here
	for(int i1=0;i1<nt1;i1++){
		BF3 bf0i=s1.bf; // restart from oldest re
		bf0i.Set(t1[i1]);
		for(int i2=0;i2<nt2;i2++){// find digits to split

			ispot2=0;// start now search in other UAs==========
			s=spots;
			s->bf=bf0i; //start with old bf plus the 2 settings
			s->bf.Set(t2[i2]);
			int iua=s1.ua;// previous UAs have a hint 
			while(++iua<nua)	if(!t[iua].Overlay(s->bf))	break;
			if(iua>=nua){return -1;}// should never be but !!!
			// we have the first free UA to start
			s->ua=iua;
next_spot:
			s->ind=-1;
			UAG & mua=t[s->ua];
			s->lim=mua.n;
			s->tt=mua.cells;
next_value:
			if(++s->ind >= s->lim) goto back_track;
			BF3 & wbf=spots[ispot2+1].bf;
			wbf=s->bf;
			wbf.Set(s->tt[s->ind]);
			iua=s->ua;
			while(++iua<nua)	if(!t[iua].Overlay(wbf))	break;
			if(iua<nua && ispot2<lim2){
				s++; ispot2++;
				s->ua=iua;
				goto next_spot;
			}
			//==================== we have one permutation to study
			if(ispot2>=lim2) goto next_value;
			if(ispot2==lim2-1){// here faster ? to check if not yet valid
			}
			ua_xy27.cpt[1]++;
			goto next_value;
back_track:
			if(--ispot2>=0) {s--; goto next_value;}
		}
	}// end i1i2
	return 0;
}

void  UA_XY27::TUAG::CoverSourceAndAll(char * p){
	BF3 wbf,wsrc; wbf.Init(); wsrc.Init();
	nuafull=nua;
	sourcecovered=0;
	for(int i=0;i<81;i++) if(p[i]-'.') wsrc.Set(i);

	for(int i=0;i<nua;i++){		
		if(t[i].IsNotIncluded(wbf)){
			t[i].omit=0;
			wbf |= t[i];
			if(wbf.IsFull()) {nuafull=++i; break;}
			if(sourcecovered==0)
				if(!wsrc.IsNotIncluded(wbf)) sourcecovered=i+1;
		}
		else	t[i].omit=1;
	}
	cout << "check ua table and source" << endl
		<< " full after " <<nuafull<<endl
		<< " source covered after " << sourcecovered<<endl;
}




int UA_XY27::TUAG::CluesBox(BF3 & mybf,int n0){
	int tbox[9][9],ntbox[9],n_to_load=0,// boxes pattern 
		tmini[54],ntmini=0,
		tob[3][2]={{1,2},{0,2},{0,1}},
		tab[10],ntab; // active boxes
	// look for unavoidales minilines 
	for(int ib=0;ib<3;ib++){// working band per band 
		if(!mybf.bf[ib]) continue; // empty band
		// assign "other bands" in game 1
		memcpy( game[1].F, game[0].F,4*54);
		for(int i2=0;i2<2;i2++){
			int ib2=tob[ib][i2],dj=27*ib2,bfx=mybf.bf[ib2];
			if(bfx){// skip empty bands
				for(int i=0;i<27;i++) if (bfx & (1<<i)){
					int cell=i+dj;
					game[1].Seta(puz0[cell],cell);
				}
			}
		}
		BF3 solved;
		game[1].FullUpdate(solved);
		if(solved.IsFull()) continue;
		// build now the table of "box_miniline" still active
		int fb=mybf.bf[ib];
		for(int i=0;i<18;i++){// work one band seen as band 1
			int n=0,fb1=fb;
			byte* mi=miniline[i];
			for(int j=0;j<3;j++){
				int cell=mi[j],bit=1<<cell;
				if(fb & bit){
					n++;
					fb1 &= ~bit; // clear bit in fb1
				}
			}
			if(n>1){// check if unavoidable, do it in game 2
				memcpy( game[2].F, game[2].F,4*54);
				int tcb[27],ntcb=String27(fb1,tcb),dj=27*ib;
				for(int i2=0;i2<ntcb;i2++){
					int cell=tcb[i2]+dj;
					game[2].Seta(puz0[cell],cell);
				}
				if(!game[2].IsPatFinalOk())tmini[ntmini++]=i+18*ib;
			}			
		}
	}
	if(ntmini){
		if(ua_xy27.cpt[0]<100)// test check the code at that point	
			cout<<ua_xy27.cpt[0]  << " ntmini= "<<ntmini  
			<< " n0=" << n0<<endl;		

	}

	// build the table of boxes and active boxes 
	for(int i=0;i<3;i++) { // bands
		int bf=mybf.bf[i],i0=27*i;// current band i0 relative first cell
		for(int j=0;j<3;j++){ // box within the band
			int box=3*i+j,&nb=ntbox[box],*tb=tbox[box];
			nb=0;
			byte * tc=cellsInGroup[j+18]; // boxes are 18-27 in cells in group
			for(int k=0;k<9;k++){
				int cell=tc[k],cellv=cell+i0;
				if(bf & (1<<cell))			tb[nb++]=cellv;				
			}
		}
	}
	ntab=0;
	for(int i=0;i<9;i++)if(ntbox[i]){
		tab[ntab++]=i;
		if(0 &&ua_xy27.cpt[1]<5)// test check the code at that point	
			cout << "active box "<<i << " n="<< ntbox[i]<<endl;		
	}
	// try to add one  box 
	for(int i=0;i<ntab;i++){  
		memcpy( game[1].F, game[0].F,4*54);
		int * tt=tbox[tab[i]],nn=ntbox[tab[i]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		if(game[1].IsPatFinalOk()) {// one box in enough 
			if(ua_xy27.cpt[0]<50)// test check the code at that point	
			cout << "one active box is enough "<<tab[i] << " n="<< ntbox[tab[i]]<<endl;		
			return n0+1; // provisoire
		}
	}
	if(n0>15) return 18; // mini will be 2 boxes
	if(ntab<3) return n0+2;
	// try to add 2 boxes 
	for(int i=0;i<ntab-1;i++)for(int i2=i+1;i2<ntab;i2++){  
		memcpy( game[1].F, game[0].F,4*54);
		int * tt=tbox[tab[i]],nn=ntbox[tab[i]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		tt=tbox[tab[i2]];
		nn=ntbox[tab[i2]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		if(game[1].IsPatFinalOk()) {// 2 boxes in enough 
			return n0+2; // provisoire
		}
	}
	if(n0>14) return 18; // mini will be 3 boxes
	if(ntab<4) return n0+3;
	// try to add 3 boxes 
	for(int i=0;i<ntab-2;i++)for(int i2=i+1;i2<ntab-1;i2++)  
	for(int i3=i2+1;i3<ntab;i3++){  
		memcpy( game[1].F, game[0].F,4*54);
		int * tt=tbox[tab[i]],nn=ntbox[tab[i]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		tt=tbox[tab[i2]];
		nn=ntbox[tab[i2]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		tt=tbox[tab[i3]];
		nn=ntbox[tab[i3]];
		for(int j=0;j<nn;j++){
			int cell=tt[j];
			game[1].Seta(puz0[cell],cell);
		}
		if(game[1].IsPatFinalOk()) {// one box in enough 
			return n0+3; // provisoire
		}
	}
	if(n0>13) return 18; // mini will be 4 boxes
	if(ntab<5) return n0+3;

	return n0+3;
}

void UA_XY27::TUAG::DumpPath(){
	cout << "progression en combinaisons niveau 1 ispot=" << ispot<<endl;
	char ws[82];
	for(int is=0;is<= ispot;is++){
		 s=&spt[is];
		 UAG & mua=t[s->ua];
		 int ind=s->ind,box=mua.tbox[ind],nb=mua.nboxclues[ind],
			 *tc=mua.boxclues[ind];
		 cout <<s->bf.String(ws)
			 << " i="<<is<<" ind=" << ind
			 << " lim="<<s->lim
			 << " ua="<<s->ua<<endl;
		 cout << "   box=" <<box<< "clues";
		 for(int j=0;j<nb;j++) cout <<tc[j]<<" ";
		 cout <<endl;
	}
	cout <<spt[ispot+1].bf.String(ws)<< "final status"<<endl;
}